﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using RoketSolutions.SP2010.Infrostructure.Common.Extensions;

namespace RoketSolutions.SP2010.Infrostructure.UI.Ajax.ValueProviders
{
    public class ValueProviderResult
    {
        public ValueProviderResult(object rawValue, string attemptedValue)
        {
            RawValue = rawValue;
            AttemptedValue = attemptedValue;
        }

        #region / Properties /

        public string AttemptedValue { get; set; }

        public object RawValue { get; set; }

        #endregion

        #region / Methods /

        public virtual object ConvertTo(Type type)
        {
            return ConvertTo(type, null);
        }

        public virtual object ConvertTo(Type type, CultureInfo culture)
        {
            if (type == null)
                throw new ArgumentNullException("type");

            var targetCulture = culture ?? CultureInfo.InvariantCulture;
            if (type.IsArray)
            {
                var arrayValue = AttemptedValue.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
                return ConvertArray(RawValue, type, targetCulture) ?? ConvertArray(arrayValue, type, targetCulture);
            }
            return ConvertValue(AttemptedValue, type, targetCulture);
        }

        protected object ConvertArray(object value, Type destinationType, CultureInfo culture)
        {
            // if destination type could be gained from value instance
            if (value == null || destinationType.IsInstanceOfType(value))
            {
                return value;
            }

            // check wheter the destination type is array
            if (destinationType.IsArray)
            {
                var elementType = destinationType.GetElementType();
                var valueArray = value as Array;
                if (valueArray != null)
                {
                    // try to convert array
                    IList convertedArray = Array.CreateInstance(elementType, valueArray.Length);
                    for(var i = 0; i < valueArray.Length; i++)
                    {
                        convertedArray[i] = ConvertValue(valueArray.GetValue(i), elementType, culture);
                    }
                    return convertedArray;
                }
                else
                {
                    // if only single item
                    var singleValue = ConvertValue(value, elementType, culture);
                    IList array = Array.CreateInstance(elementType, 1);
                    array[0] = singleValue;
                    return array;
                }
            }

            return null;
        }

        protected object ConvertValue(object value, Type destinationType, CultureInfo culture)
        {
            // if destination type could be extracted from value instance
            if (value == null || destinationType.IsInstanceOfType(value))
            {
                return value;
            }

            // if empty value
            if (value.ToString().IsNullOrEmpty())
                return null;

            // get possible converter for types
            var converter = TypeDescriptor.GetConverter(destinationType);
            var canConvertFromValueType = converter.CanConvertFrom(value.GetType());
            if (!canConvertFromValueType)
            {
                converter = TypeDescriptor.GetConverter(value.GetType());
                if (!converter.CanConvertTo(destinationType))
                {
                    throw new InvalidOperationException(string.Format("No convert exists for type '{0}' to destination type '{1}'", value.GetType().Name, destinationType.Name));
                }
            }

            // convert value
            return canConvertFromValueType
                           ? converter.ConvertFrom(null, culture, value)
                           : converter.ConvertTo(null, culture, value, destinationType);
        }

        #endregion
 

    }
}